// ==================================================================================
// Shared Genomics Project MPI Codebase
// Version 1.0 30/04/2010
//
// (c) 2010 University of Manchester all rights reserved
//
// This file is distributed under the GNU General Public License, Version 2.  
// Please see the file COPYING.txt for more details
// ==================================================================================

/*!
\file
\brief	Linear Model (Design Matrix)
*/
#ifndef _LINEAR_MODEL_H_
#define _LINEAR_MODEL_H_

#include "bmapfile.h"
#include "ipedfile.h"
#include "_int2.h"
#include "options.h"
#include "sample.h"
#include "types.h"

#ifdef __cplusplus
extern "C" {
#endif

/*!
\file
\brief	Linear Model (Design Matrix)
\ingroup pepi_qt
\details
	This model was <em>reversed engineered</em> straight from PLINK.
	It's main job is to create a design matrix for \ref pepi_qt to model the interaction between 2 SNPs.
	Once a design matrix is created, it is passed to a SVD function for solution 
	and the generation of a test stastistic.
	Memory bound to the structure is re-used for a series of epistasis interaction calculations
	by invoking the appropriate accessor functions for the the structure.
*/
struct linear_model {
	BOOL *miss; // Missing array.
	int nMiss;
	int dimension;
	BOOL *haploid, *xchr;
	int *additive;
	struct INT2 interaction[1];
	int nInteraction; // Max index in array, use to control loops.
	MATRIX_T X;
	int nX;
	int X_max_used; // Index flag to show which numbers of X-rows actually included in the analysis matrix.
	int np; // Main effects + interaction + intercept
	int mAA, mAB, mBB;
	BOOL all_valid;

	// Dependent variables.
	int nind; // these array controlled by nind.
	VECTOR_T p, Y;
	
	// FIT LM variables
	VECTOR_T coef, sig, w, b; 
	MATRIX_T S, u, v, Xt, S0, S0_inverse;
	VECTOR_T V; // diagonal p(1-p) 
	int nU;
	double varY, chisq;
	BOOL *valid; 
	BOOL cluster; // Clustering behavior associated with FitLM function.
};

/*!
\brief Initialise the %Linear Model
\details 
	Set things to NULL or zero.
	This sub-routine does no checking for pre-assignment of memory 
	so calling this function twice when memory has been assigned will cause a memory leak.
\param [in,out] p Pointer to a \ref linear_model structure
\returns void
*/
int linear_model_init(struct linear_model *p);

/*!
\brief Free memory bound to %Linear Model
\details 
	Free the bound memory (i.e. attributes) bound to the linear model.
	Assumes all pointers are NULL initialised and NULL checks before deallocating.
	Before using the linear_model, you must call linear_model_init() to initialise
	all of the required pointers.
\param [in,out] lm Pointer to a \ref linear_model structure
\returns 1 on success, 0 on failure 
\sa linear_model_init()
*/
int linear_model_free_attributes(struct linear_model *lm);

/*! 
\brief Set the No. parameters in the linear model.
\details
	The width of the design matrix is referred to as 'np' within the PLINK codebase.
	The np value set of this method is the design matrix width required by the epistasis (BT).
\param [in,out] lm Pointer to a \ref linear_model structure
\param [in] ops Adds sex effect column to the design matrix
\sa selected_options::sex_effect
\returns void
*/
void linear_model_set_np(struct linear_model *lm, struct selected_options *ops);

/*!
\brief Allocates memory to the linear model
\details
	Allocates memory to the model for a given %sample size.
	No checking prior to allocation, repeat calls of this function will produce a memory leak.
\param [in,out] lm Pointer to a linear model
\param [in] nSamples Number of samples
\return 1 on success, 0 on failure
*/
int linear_model_alloc(struct linear_model *lm, int nSamples);

/*!
\brief Populates the design matrix with the phenotype array.
\details
	Populates the design matrix with the phenotype array.
	Main method of getting randomised phenotypes into the design matrix of the linear model.
\param [in,out] lm Pointer to a linear model
\param [in] samples Pointer to the samples array
\param [in] nSamples Size of the %sample array.
\returns 1 on success, 0 on failure
*/
int linear_model_set_dependent(struct linear_model *lm, struct sample *samples, int nSamples);

/*!
\brief Set the variance of the Linear Model 
\param [in,out] lm Pointer to a linear model
\returns 1 on success, 0 on failure
*/
int linear_model_set_variance(struct linear_model *lm);

/*!
\brief Add SNP co-ordinates to the design matrix
\details
    Method called twice when used in a epistasis calculation.
	First main effect SNP is given dimension_index=0, 2nd SNP main effect SNP is given dimension_index=1.
	Method set if SNP is haploid or diploid in the design matrix.
\param [in,out] lm Pointer to a linear model
\param [in] chromos Pointer to the chromosal model
\param [in] m Pointer to a Locus
\param [in] snp_index SNP index in the data-set.
\param [in] dimension_index Dimension (0 or 1).
\returns 1 on success, 0 on failure
*/
int linear_model_add_additive_snp(struct linear_model *lm, struct chromosomes *chromos, struct small_locus *m, int snp_index, int dimension_index);

/*!
\brief Build the Design Matrix
\details
    Build the design matrix using the allelic data.
\param [in,out] lm Pointer to a linear model
\param [in] ipedData Pointer to the individual major allelic data
\param [in] samples Pointer to the samples array
\param [in] nSamples Size of the %sample array
\param [in] nIpedRecordSizeInBytes Size of a SNP record in the allelic data array
\param [in] ops Analysis options (\ref selected_options::sex_effect)
\returns 1 on success, 0 on failure
*/
enum MATHS_RETURN linear_model_build_design_matrix(struct linear_model *lm, char *ipedData, struct sample *samples, int nSamples, int nIpedRecordSizeInBytes, struct selected_options *ops);

/*!
\brief Fits the linear model with data and attempt a solution with SVD.
\param [in,out] lm Pointer to a linear model
\returns \ref MATHS_RETURN (this return value is a bit overly complicated and will be removed in a future release)
*/
enum MATHS_RETURN linear_model_fitLM(struct linear_model *lm);

/*!
\brief Calculates the parameter array (S) bound to the linear model.
\param [in,out] lm Pointer to a linear model
\returns \ref MATHS_RETURN (this return value is a bit overly complicated and will be removed in a future release)
*/
enum MATHS_RETURN linear_model_validParameters(struct linear_model *lm);

/*!
\brief Get the test statistic associated with the linear model.
\param [in,out] lm Pointer to a linear model
\param [in] testParameter Index in the co-efficient array of the linear model which contains the test statistic.
\returns \ref MATHS_RETURN (this return value is a bit overly complicated and will be removed in a future release)
*/
double linear_model_get_statistic(struct linear_model *lm, int testParameter);

#ifdef __cplusplus
}
#endif

#endif